package Verifier.ArithmeticSystem;

import java.math.BigInteger;
import Verifier.ByteTree.ByteTree;
import Verifier.Marshal.MarshalParser;

public class ArithmeticConvertorGroupTester {
	
	static ModularGroup g = null;
	static ProductGroup gSquare = null;

	private static void test() {
		try {
			ModularGroup g = (ModularGroup)MarshalParser.Unmarshal(new ByteTree("0000000002010000001c766572696669636174756d2e61726974686d2e4d6f645047726f75700000000004010000008101d9f27f10e6a62b003160daea5bed498c3dc4fcbf5d4badf230ec7937cf171dc024acfee3a0064f8627319092868724b3afdd0127eafc2187f251da5d0ce61e1ed31fd33afa2edc53174fc19c3c08cc8672b85fc495003494ae78f108f050a5c1753a8a44f33f67e2a7f0b38613292550c84e7af73bb8e7575de384594a85f97b010000008100ecf93f887353158018b06d752df6a4c61ee27e5faea5d6f918763c9be78b8ee012567f71d00327c31398c84943439259d7ee8093f57e10c3f928ed2e86730f0f698fe99d7d176e298ba7e0ce1e046643395c2fe24a801a4a573c7884782852e0ba9d4522799fb3f153f859c3099492a864273d7b9ddc73abaef1c22ca542fcbd0100000081006b7a73aa9a596835f2ef0ff5a78c9bd48fe4e4300c8a4ef417649409f26c9b0c850758e6c15ccb6358a1a2478532bad3fc1052745a48e49843f825d56afb4553a1373bb0a785b7513a898233cbddee18842bd4c187fc1378577d0fb8765c3d220ac015ab87b5b99de23afdfeb3bddd3e972baac00cd5f16b7faa402dddff4238010000000400000001"));
			printGroup(g, 16);
			System.out.println();
			System.out.println(ArithmeticConvertor.ToByteTree(g.getGroupCreatorAsGroupElement()).getByteString());
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			if (!testModularGroup(new ModularGroup(BigInteger.valueOf(263), BigInteger.valueOf(131), BigInteger.valueOf(235), 1)
					, "00000000040100000002010701000000020083010000000200EB010000000400000001"))
			{ return; }
		} catch (Exception e1) {
			e1.printStackTrace();
			return;
		}
		System.out.println();
		try {
			if (!testModularGroupElement(new ModularGroupElement(BigInteger.valueOf(25), g), "01000000020019"))
			{ return; }
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
		System.out.println();
		
		try {
			gSquare = new ProductGroup(new Group[] { g, g });
		} catch (Exception e1) {
			e1.printStackTrace();
			return;
		}
		System.out.println();
		
		ProductGroupElement prodResult = null;
		try {
			prodResult = new ProductGroupElement(gSquare);
			prodResult.addGroupElement(new ModularGroupElement(BigInteger.valueOf(258), g));
			prodResult.addGroupElement(new ModularGroupElement(BigInteger.valueOf(25), g));
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
		if (!testModularGroupProduct(prodResult, "00000000020100000002010201000000020019"))
		{ return; }
		System.out.println();
		ModularGroupElement[] elements = new ModularGroupElement[5];
		try {
			elements[0] = new ModularGroupElement(BigInteger.valueOf(258), g);
			elements[1] = new ModularGroupElement(BigInteger.valueOf(11), g);
			elements[2] = new ModularGroupElement(BigInteger.valueOf(172), g);
			elements[3] = new ModularGroupElement(BigInteger.valueOf(95), g);
			elements[4] = new ModularGroupElement(BigInteger.valueOf(26), g);
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
		
		if (!testModularGroupArray(elements, "0000000005010000000201020100000002000B010000000200AC0100000002005F0100000002001A"))
		{ return; }
		System.out.println();
		
		ProductGroupElement[] pElements = new ProductGroupElement[3];
		try {
			pElements[0] = new ProductGroupElement(gSquare);
			pElements[0].addGroupElement(new ModularGroupElement(BigInteger.valueOf(258), g));
			pElements[0].addGroupElement(new ModularGroupElement(BigInteger.valueOf(11), g));
			pElements[1] = new ProductGroupElement(gSquare);
			pElements[1].addGroupElement(new ModularGroupElement(BigInteger.valueOf(172), g));
			pElements[1].addGroupElement(new ModularGroupElement(BigInteger.valueOf(95), g));
			pElements[2] = new ProductGroupElement(gSquare);
			pElements[2].addGroupElement(new ModularGroupElement(BigInteger.valueOf(26), g));
			pElements[2].addGroupElement(new ModularGroupElement(BigInteger.valueOf(235), g));
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
		
		if (!testModularGroupProductArray(pElements, "0000000002000000000301000000020102010000000200AC0100000002001A00000000030100000002000B0100000002005F010000000200EB"))
		{ return; }
		System.out.println();
		test();
	}
	
	private static void printGroup(ModularGroup group, int radix) {
		System.out.print("(\n\tp: " + group.getContainingGroupOrder().toString(radix) + "\n\tq: " + group.getOrder().toString(radix) + 
			"\n\tg: " + group.getGroupCreator().toString(radix) + "\n\te: " + group.getEncodingScheme() + "\n)");
	}
	
	private static boolean testModularGroup(ModularGroup resultGroup, String treeString) {
		System.out.println("Test : Modular Group");
		System.out.println("--------------------");
		// convert the byte tree into a modular group
		System.out.print("Create Modular Group of ");
		printGroup(resultGroup, 10);
		System.out.println();
		
		try {
			g = ArithmeticConvertor.ToModularGroup(new ByteTree(treeString));
			if (!g.equals(resultGroup)) {
				System.out.println("Failed : the modular group created is different from the result");
				return (false);
			}
			System.out.println("OK : Modular Group created");
		} catch (Exception e) {
			System.out.println("Failed : creating the modular group");
			return (false);
		}
		
		System.out.print("The Modular Group created is: ");
		printGroup(g, 10);
		System.out.println();
		
		// convert the modular group into a byte tree
		System.out.println("Converting the modular group backwards:");
		try {
			ByteTree b = ArithmeticConvertor.ToByteTree(g);
			
			if (0 == b.getByteString().compareToIgnoreCase(treeString)) {
				System.out.println("OK : The created byte tree is the same as the one that created the group");
			} else {
				System.out.println("Failed : The created byte tree is the different as the one that created the group");
				System.out.println(b.getByteString());
				System.out.println(treeString);
			}
		} catch (Exception e) {
			System.out.println("Failed to create the byte tree");
			return (false);
		}
		
		return (true);
	}
	
	private static boolean testModularGroupElement(ModularGroupElement resultElement, String treeString) {
		System.out.println("Test : Modular Group Element");
		System.out.println("----------------------------");
		// convert the byte tree into a modular group
		System.out.println("Create Modular Group Element : e = " + resultElement.getElement());
		GroupElement e = null;
		try {
			e = ArithmeticConvertor.ToGroupElement(new ByteTree(treeString), g);
			if (!e.equals(resultElement)) {
				System.out.println("Failed : the modular group element created is different from the result");
				return (false);
			}
			System.out.println("OK : Modular Group Element created");
		} catch (Exception ex) {
			System.out.println("Failed : creating the modular group element");
			return (false);
		}
		
		System.out.println("The Modular Group Element created is: " + ((ModularGroupElement)e).getElement());
		
		// convert the modular group into a byte tree
		System.out.println("Converting the modular group element backwards:");
		try {
			ByteTree b = ArithmeticConvertor.ToByteTree(e);
			
			if (0 == b.getByteString().compareToIgnoreCase(treeString)) {
				System.out.println("OK : The created byte tree is the same as the one that created the element");
			} else {
				System.out.println("Failed : The created byte tree is the different as the one that created the element");
				System.out.println(b.getByteString());
				System.out.println(treeString);
			}
		} catch (Exception ex) {
			System.out.println("Failed to create the byte tree");
			return (false);
		}
		
		return (true);
	}
	
	private static void printProductGroupElement(ProductElement groupProduct) {
		System.out.print("(");
		for (int i = 0 ; i < groupProduct.getNumberOfElements(); i++) {
			GroupElement element = groupProduct.getElement(i);
			if (element instanceof ModularGroupElement) {
				System.out.print(((ModularGroupElement)element).getElement());
			} else {
				printProductGroupElement((ProductElement)element);
			}
			if (i + 1 < groupProduct.getNumberOfElements()) {
				System.out.print(",");
			}
		}
		System.out.print(")");
	}
	
	private static boolean testModularGroupProduct(ProductGroupElement resultElement, String treeString) {
		System.out.println("Test : Product Group Element");
		System.out.println("----------------------------");
		// convert the byte tree into a modular group
		System.out.print("Create Product Group Element : ");
		printProductGroupElement(resultElement);
		System.out.println();
		
		ProductElement groupProduct = null;
		try {
			groupProduct = ArithmeticConvertor.ToProductElement(new ByteTree(treeString), gSquare);
			if (!groupProduct.equals(resultElement)) {
				System.out.println("Failed : the product group element created is different from the result");
				return (false);
			}
			System.out.println("OK : Product Group Element created");
			
		} catch (Exception e) {
			System.out.println("Failed : to create product group element");
			return (false);
		}
		System.out.print("The result product group element:");
		printProductGroupElement(groupProduct);
		System.out.println();
		
		// convert the modular group into a byte tree
		System.out.println("Converting the product group element backwards:");
		try {
			ByteTree b = ArithmeticConvertor.ToByteTree(groupProduct);
			
			if (0 == b.getByteString().compareToIgnoreCase(treeString)) {
				System.out.println("OK : The created byte tree is the same as the one that created the element");
			} else {
				System.out.println("Failed : The created byte tree is the different as the one that created the element");
				System.out.println(b.getByteString());
				System.out.println(treeString);
			}
		} catch (Exception e) {
			System.out.println("Failed to create the byte tree");
			return (false);
		}
		
		return (true);
	}
	
	private static void printModularGroupArray(GroupElement[] elements) {
		System.out.print("[");
		for (int i = 0 ; i < elements.length; i++) {
			System.out.print(((ModularGroupElement)elements[i]).getElement());
			if (i + 1 < elements.length) {
				System.out.print(",");
			}
		}
		System.out.print("]");
	}
	
	private static boolean testModularGroupArray(ModularGroupElement[] resultElement, String treeString) {
		System.out.println("Test : Array of Modular Group Element");
		System.out.println("-------------------------------------");
		// convert the byte tree into a modular group
		System.out.print("Create Array of Modular Group Element : ");
		printModularGroupArray(resultElement);
		System.out.println();
		
		GroupElement[] elements = null;
		try {
			elements = ArithmeticConvertor.ToGroupElementArray(new ByteTree(treeString), g);
			if (elements.length != resultElement.length) {
				System.out.println("Failed : the modular group element array created is different from the result by their sizes");
				return (false);
			}
			for (int i = 0; i < elements.length; i++) {
				if (!elements[i].equals(resultElement[i])) {
					System.out.println("Failed : the modular group element no." + i + " created is different from the result");
					return (false);
				}				
			}
			
			System.out.println("OK : Array of Modular Group Elements created");
			
		} catch (Exception e) {
			System.out.println("Failed : to create Array of Modular Group Elements");
			return (false);
		}
		System.out.print("The result Array of Modular Group Elements:");
		printModularGroupArray(elements);
		System.out.println();
		
		// convert the modular group into a byte tree
		System.out.println("Converting the Array of Modular Group Elements backwards:");
		try {
			ByteTree b = ArithmeticConvertor.ToByteTree(elements);
			
			if (0 == b.getByteString().compareToIgnoreCase(treeString)) {
				System.out.println("OK : The created byte tree is the same as the one that created the element");
			} else {
				System.out.println("Failed : The created byte tree is the different as the one that created the element");
				System.out.println(b.getByteString());
				System.out.println(treeString);
			}
		} catch (Exception e) {
			System.out.println("Failed to create the byte tree");
			return (false);
		}
		
		return (true);
	}
	
	private static void printModularGroupProductArray(ProductElement[] elements) {
		System.out.print("[");
		for (int i = 0 ; i < elements.length; i++) {
			printProductGroupElement(elements[i]);
			if (i + 1 < elements.length) {
				System.out.print(",");
			}
		}
		System.out.print("]");
	}
	
	private static boolean testModularGroupProductArray(ProductGroupElement[] resultElement, String treeString) {
		System.out.println("Test : Array of Product Group Element");
		System.out.println("-------------------------------------");
		// convert the byte tree into a modular group
		System.out.print("Create Array of Product Group Element : ");
		printModularGroupProductArray(resultElement);
		System.out.println();
		
		ProductElement[] elements = null;
		try {
			elements = ArithmeticConvertor.ToProductElementArray(new ByteTree(treeString), gSquare);
			if (elements.length != resultElement.length) {
				System.out.println("Failed : the product group element array created is different from the result by their sizes");
				return (false);
			}
			for (int i = 0; i < elements.length; i++) {
				if (!elements[i].equals(resultElement[i])) {
					System.out.println("Failed : the product group element no." + i + " created is different from the result");
					return (false);
				}				
			}
			
			System.out.println("OK : Array of Product Group Elements created");
		} catch (Exception e) {
			System.out.println("Failed : to create Product of Modular Group Elements");
			return (false);
		}
		System.out.print("The result Array of Product Group Elements:");
		printModularGroupProductArray(elements);
		System.out.println();
		
		// convert the modular group into a byte tree
		System.out.println("Converting the Array of Product Group Elements backwards:");
		try {
			ByteTree b = ArithmeticConvertor.ToByteTree(elements);
			
			if (0 == b.getByteString().compareToIgnoreCase(treeString)) {
				System.out.println("OK : The created byte tree is the same as the one that created the element");
			} else {
				System.out.println("Failed : The created byte tree is the different as the one that created the element");
				System.out.println(b.getByteString());
				System.out.println(treeString);
			}
		} catch (Exception e) {
			System.out.println("Failed to create the byte tree");
			return (false);
		}
		
		return (true);
	}
}
